;
if (nv.CreateNamespace('nv.Event') && nv.CreateNamespace('nv.Events')) {
    nv.Event = function (maintainHistory) {
        var $this = this;
        if (typeof (maintainHistory) === "undefined") {
            maintainHistory = false;
        } else if (maintainHistory === true) {
            maintainHistory = nv.Event.MAINTAIN_HISTORY_ALL;
        }
        var historyOfEvents = new Array();
        var callbacks = [];
        var toBind = null;
        var delayUnbind = false;
        var triggerCounter = 0;
        var firstBind = true;
        var firstBindCallback = null;
        $this.bind = $this.Bind = function (callback, secondparam) {
            var unbindOnTrigger = (secondparam === true);
            if (typeof secondparam == 'object') {
                nv.$(secondparam).bind("remove", function () {
                    $this.unbind(callback);
                });
            }
            if (firstBind && typeof firstBindCallback == 'function') {
                firstBindCallback.call(null, $this);
                firstBind = false;
            }
            if (!unbindOnTrigger || historyOfEvents.length == 0) {
                (toBind || callbacks).push({
                    callback: callback,
                    unbindOnTrigger: unbindOnTrigger
                });
            }
            if (maintainHistory === nv.Event.MAINTAIN_HISTORY_ALL) {
                for (var i = 0; i < historyOfEvents.length; i++) {
                    callback.apply(this, historyOfEvents[i]);
                }
            } else if (maintainHistory === nv.Event.MAINTAIN_HISTORY_LAST) {
                if (historyOfEvents.length > 0) callback.apply(this, historyOfEvents[historyOfEvents.length - 1]);
            }
        };
        $this.bindOnce = function (callback) {
            $this.bind(callback, true);
        };
        $this.unbind = $this.Unbind = function (callbackToBeUnbound) {
            for (var i = 0; i < callbacks.length; i++) {
                var callback = callbacks[i];
                if (callback.callback == callbackToBeUnbound) {
                    if (delayUnbind) {
                        callback.unbound = true;
                    } else {
                        callbacks.splice(i, 1);
                    }
                    break;
                }
            }
        };
        $this.reset = $this.Reset = function () {
            callbacks = [];
            toBind = null;
            delayUnbind = false;
            historyOfEvents = [];
            firstBind = true;
        };
        var _trigger = function (args) {
            var alreadyInside = toBind != null;
            if (!alreadyInside) {
                toBind = [];
                delayUnbind = true;
            }
            if (maintainHistory === nv.Event.MAINTAIN_HISTORY_ALL) {
                historyOfEvents.push(args);
            } else if (maintainHistory === nv.Event.MAINTAIN_HISTORY_LAST) {
                historyOfEvents[0] = args;
            }
            for (var i = 0; i < callbacks.length; i++) {
                var callback = callbacks[i];
                if (callback.unbound === true) {
                    continue;
                }
                if (callback.unbindOnTrigger) {
                    callback.unbound = true;
                }
                callback.callback.apply(this, args);
            }
            if (!alreadyInside) {
                for (var i = callbacks.length - 1; i >= 0; --i) {
                    if (callbacks[i].unbound === true) {
                        callbacks.splice(i, 1);
                    }
                }
                Array.prototype.push.apply(callbacks, toBind);
                toBind = null;
                delayUnbind = false;
            }
            triggerCounter++;
        };
        $this.trigger = $this.Trigger = function () {
            var args = Array.prototype.slice.call(arguments);
            if (nv.Events.paused) {
                nv.Events.paused.push(function () {
                    _trigger(args);
                });
                return;
            }
            _trigger(args);
        };
        $this.HasTriggered = function () {
            return triggerCounter > 0;
        };
        $this.lastHistory = function () {
            return historyOfEvents.length > 0 && historyOfEvents[historyOfEvents.length - 1];
        };
        $this.clearHistory = function () {
            historyOfEvents = [];
        };
        $this.setFirstBindCallback = function (callback) {
            firstBindCallback = callback;
        };
        $this.hasListeners = function () {
            return callbacks.length > 0;
        };
    };
    nv.Event.MAINTAIN_HISTORY_LAST = 'maintainHistoryLast';
    nv.Event.MAINTAIN_HISTORY_ALL = 'maintainHistoryAll';
    nv.Events = new function () {
        var $this = this;
        var list = {};
        $this.paused = null;
        $this.pause = function () {
            if (!$this.passed) $this.paused = [];
        };
        $this.resume = function () {
            var waiting = null;
            while ((waiting = $this.paused.shift())) {
                waiting();
            }
            $this.paused = null;
        };
        $this.Bind = function (name, callback, unbindOnTrigger) {
            if (list[name] === undefined) {
                list[name] == new nv.Event(false);
            }
            list[name].Bind(callback, unbindOnTrigger);
        };
        $this.Trigger = function (name, e) {
            if (list[name] === undefined) {
                list[name] == new nv.Event();
            }
            list[name].Trigger(e);
        };
        $this.Unbind = function (name, callback) {
            if (list[name] !== undefined) {
                list[name].Unbind(callback);
            }
        };
    };
}